#ifndef BASE_PROXYSERVER_H_
#define BASE_PROXYSERVER_H_

#include <list>
#include "asyncsocket.h"
#include "socketadapters.h"
#include "socketaddress.h"
#include "stream.h"

namespace base {

	class SocketFactory;

	// ProxyServer is a base class that allows for easy construction of proxy
	// servers. With its helper class ProxyBinding, it contains all the necessary
	// logic for receiving and bridging connections. The specific client-server
	// proxy protocol is implemented by an instance of the AsyncProxyServerSocket
	// class; children of ProxyServer implement WrapSocket appropriately to return
	// the correct protocol handler.

	class ProxyBinding : public sigslot::has_slots<> {
	public:
		ProxyBinding(AsyncProxyServerSocket* in_socket, AsyncSocket* out_socket);
		sigslot::signal1<ProxyBinding*> SignalDestroyed;

	private:
		void OnConnectRequest(AsyncProxyServerSocket* socket,
			const SocketAddress& addr);
		void OnInternalRead(AsyncSocket* socket);
		void OnInternalWrite(AsyncSocket* socket);
		void OnInternalClose(AsyncSocket* socket, int err);
		void OnExternalConnect(AsyncSocket* socket);
		void OnExternalRead(AsyncSocket* socket);
		void OnExternalWrite(AsyncSocket* socket);
		void OnExternalClose(AsyncSocket* socket, int err);

		static void Read(AsyncSocket* socket, FifoBuffer* buffer);
		static void Write(AsyncSocket* socket, FifoBuffer* buffer);
		void Destroy();

		static const int kBufferSize = 4096;
		scoped_ptr<AsyncProxyServerSocket> int_socket_;
		scoped_ptr<AsyncSocket> ext_socket_;
		bool connected_;
		FifoBuffer out_buffer_;
		FifoBuffer in_buffer_;
		DISALLOW_EVIL_CONSTRUCTORS(ProxyBinding);
	};

	class ProxyServer : public sigslot::has_slots<> {
	public:
		ProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr,
			SocketFactory* ext_factory, const SocketAddress& ext_ip);
		virtual ~ProxyServer();

	protected:
		void OnAcceptEvent(AsyncSocket* socket);
		virtual AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) = 0;
		void OnBindingDestroyed(ProxyBinding* binding);

	private:
		typedef std::list<ProxyBinding*> BindingList;
		SocketFactory* ext_factory_;
		SocketAddress ext_ip_;
		scoped_ptr<AsyncSocket> server_socket_;
		BindingList bindings_;
		DISALLOW_EVIL_CONSTRUCTORS(ProxyServer);
	};

	// SocksProxyServer is a simple extension of ProxyServer to implement SOCKS.
	class SocksProxyServer : public ProxyServer {
	public:
		SocksProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr,
			SocketFactory* ext_factory, const SocketAddress& ext_ip)
			: ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {
		}
	protected:
		AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) {
			return new AsyncSocksProxyServerSocket(socket);
		}
		DISALLOW_EVIL_CONSTRUCTORS(SocksProxyServer);
	};

}  // namespace base

#endif  // BASE_PROXYSERVER_H_
